package imp

import (
	sqlc "bgs/db/sqlc"
	activityUserAwardGrpc "bgs/grpc/gen/service/activity_user_award"
	"bgs/grpc/gen/shared/message"
	"bgs/service/model"
	"bgs/util"
	"context"
	"encoding/json"
	"fmt"
)

/****************************************************************************************/
/*                               activity_user_procedure entity of helper               */
/****************************************************************************************/

func transRealPrizeSkuToPb(o *model.RealPrizeSku) *activityUserAwardGrpc.RealPrizeSkuEntity {
	return &activityUserAwardGrpc.RealPrizeSkuEntity{
		ProductId:     o.ProductID,
		ProductSpecId: o.ProductSpecID,
		Price:         o.Price,
		StorageKey:    o.StorageKey,
		// product_spec info
		SkuName: o.SkuName,
	}
}

func mapRealPrizeSkuEntityToPb(list []*model.RealPrizeSku, f func(*model.RealPrizeSku) *activityUserAwardGrpc.RealPrizeSkuEntity) []*activityUserAwardGrpc.RealPrizeSkuEntity {
	r := make([]*activityUserAwardGrpc.RealPrizeSkuEntity, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

func transformRealPrizeProductEntityToPb(ptr *model.RealPrizeProduct) *activityUserAwardGrpc.RealPrizeProductEntity {
	return &activityUserAwardGrpc.RealPrizeProductEntity{
		ProductId:            ptr.ProductID,
		ProductName:          ptr.ProductName,
		ProductPics:          ptr.ProductPics,
		PriceMin:             ptr.PriceMin,
		PriceMax:             ptr.PriceMax,
		Quantity:             ptr.Quantity,
		ProductAttributeDefs: mapProductAttributeDefsToPb(ptr.AttributeDefs, transProductAttributeDefsToPb),
		Skus:                 mapRealPrizeSkuEntityToPb(ptr.SkuPtrs, transRealPrizeSkuToPb),
	}
}

func mapRealPrizeProductEntityToPb(list []*model.RealPrizeProduct, f func(*model.RealPrizeProduct) *activityUserAwardGrpc.RealPrizeProductEntity) []*activityUserAwardGrpc.RealPrizeProductEntity {
	r := make([]*activityUserAwardGrpc.RealPrizeProductEntity, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

func transformActivityUserAwardForCEntityToPb(o sqlc.ListActivityUserAwardsWithOrderInfoByActivityIDAndUserIDAndAwardTypeRow) *activityUserAwardGrpc.ActivityUserAwardForCEntity {
	extInfoPtr := &model.ActivityUserAwardExtInfo{}
	json.Unmarshal(o.ExtInfo, extInfoPtr)

	v := &activityUserAwardGrpc.ActivityUserAwardForCEntity{
		AwardId:                o.ID,
		BrandId:                o.BrandID,
		ActivityId:             o.ActivityID,
		UserId:                 o.UserID,
		Awarded:                sqlc.GoTimeToPBTimestamp(o.Awarded),
		NeedRedeemByMannual:    o.NeedRedeemByMannual,
		RedeemDeadlineAt:       sqlc.GoTimeToPBTimestamp(o.RedeemDeadlineAt),
		IsRedeemed:             o.IsRedeemed,
		Redeemed:               sqlc.GoNTimeToPBTimestamp(o.Redeemed),
		OrderSerialNumber:      o.OrderSerialNumber.String,
		OrderPaymentDeadlineAt: sqlc.GoTimeToPBTimestamp(o.OrderPaymentDeadlineAt),
		AwardType:              o.AwardType,
		BrandName:              extInfoPtr.BrandName,
		BrandTel:               extInfoPtr.BrandTel,
		ActivityName:           extInfoPtr.ActivityName,
		ActivityType:           extInfoPtr.ActivityType,
		ActivityTel:            extInfoPtr.ActivityTel,
		WinnerNickName:         extInfoPtr.WinnerNickName,
		WinnerPic:              extInfoPtr.WinnerPic,
		WinnerTel:              extInfoPtr.WinnerTel,
		WarehouseId:            extInfoPtr.WarehouseID,
		DeliveryModes:          extInfoPtr.DeliveryModes,
		ShippingFee:            extInfoPtr.ShippingFee,
	}

	switch sqlc.EmAwardType(o.AwardType) {
	case sqlc.EmAwardTypeBCoin:
		v.BCoins = uint32(extInfoPtr.AwardInfo.Coins)
	case sqlc.EmAwardTypeRealPrize:
		v.RealPrizeProducts = mapRealPrizeProductEntityToPb(extInfoPtr.AwardInfo.RealPrizePtrs, transformRealPrizeProductEntityToPb)
	}
	return v
}

func mapActivityUserAwardForCEntityToPb(list []sqlc.ListActivityUserAwardsWithOrderInfoByActivityIDAndUserIDAndAwardTypeRow, f func(sqlc.ListActivityUserAwardsWithOrderInfoByActivityIDAndUserIDAndAwardTypeRow) *activityUserAwardGrpc.ActivityUserAwardForCEntity) []*activityUserAwardGrpc.ActivityUserAwardForCEntity {
	r := make([]*activityUserAwardGrpc.ActivityUserAwardForCEntity, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

func transformActivityAwardAsReporterEntityToPb(o sqlc.ListActivityUserAwardWithUserInfosByActivityIDRow) *activityUserAwardGrpc.ActivityAwardAsReporterEntity {
	extInfoPtr := &model.ActivityUserAwardExtInfo{}
	json.Unmarshal(o.ExtInfo, extInfoPtr)

	v := &activityUserAwardGrpc.ActivityAwardAsReporterEntity{
		UserNickName: o.UserNickName,
		Awarded:      sqlc.GoTimeToPBTimestamp(o.Awarded),
	}

	switch sqlc.EmAwardType(o.AwardType) {
	case sqlc.EmAwardTypeBCoin:
		v.Desc = fmt.Sprintf("抽到了%d个星币", uint32(extInfoPtr.AwardInfo.Coins))
	case sqlc.EmAwardTypeRealPrize:
		v.Desc = fmt.Sprintf("抽到了%s", util.JoinString(util.MapToString(util.ToGenericSlice(extInfoPtr.AwardInfo.RealPrizePtrs), func(v interface{}) string {
			val := v.(*model.RealPrizeProduct)
			return val.ProductName
		}), ";"))
	}
	return v
}

func mapActivityAwardAsReporterEntityToPb(list []sqlc.ListActivityUserAwardWithUserInfosByActivityIDRow, f func(sqlc.ListActivityUserAwardWithUserInfosByActivityIDRow) *activityUserAwardGrpc.ActivityAwardAsReporterEntity) []*activityUserAwardGrpc.ActivityAwardAsReporterEntity {
	r := make([]*activityUserAwardGrpc.ActivityAwardAsReporterEntity, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

/****************************************************************************************/
/*                               activity_user_award entity of cmd                      */
/****************************************************************************************/

/****************************************************************************************/
/*                               activity_user_award entity of query                    */
/****************************************************************************************/

// ListActivityUserAwardsByActivityIDAndUserIDAndAwardType C端用户获取自身中奖记录
func (s *ActivityAPIService) ListActivityUserAwardsByActivityIDAndUserIDAndAwardType(ctx context.Context, req *activityUserAwardGrpc.ListActivityUserAwardsByActivityIDAndUserIDAndAwardTypeRequest) (res *activityUserAwardGrpc.ListActivityUserAwardsByActivityIDAndUserIDAndAwardTypeResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("activity_user_awardImp->ListActivityUserAwardsByActivityIDAndUserIDAndAwardType:%v", req)
	res = &activityUserAwardGrpc.ListActivityUserAwardsByActivityIDAndUserIDAndAwardTypeResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}

	q := s.dao.Q
	ts := sqlc.PBTimestampToGoTime(req.Ts)
	activityID := req.ActivityId
	userID := req.UserId
	awardType := req.AwardType

	total, err := q.CountActivityUserAwardsByActivityIDAndUserIDAndAwardType(ctx, sqlc.CountActivityUserAwardsByActivityIDAndUserIDAndAwardTypeParams{
		Created:    ts,
		ActivityID: activityID,
		UserID:     userID,
		AwardType:  awardType,
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	if total == 0 {
		// 不用继续调用listfunc
		return
	}

	rows, err := q.ListActivityUserAwardsWithOrderInfoByActivityIDAndUserIDAndAwardType(ctx, sqlc.ListActivityUserAwardsWithOrderInfoByActivityIDAndUserIDAndAwardTypeParams{
		Limit:      req.Limit,
		Offset:     req.Offset,
		Created:    ts,
		ActivityID: activityID,
		UserID:     userID,
		AwardType:  awardType,
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.Total = total
	res.ActivityUserAwards = mapActivityUserAwardForCEntityToPb(rows, transformActivityUserAwardForCEntityToPb)
	return
}

// ListActivityAwardsByActivityIDAsReporter C端用户获取活动中奖纪录
func (s *ActivityAPIService) ListActivityAwardsByActivityIDAsReporter(ctx context.Context, req *activityUserAwardGrpc.ListActivityAwardsByActivityIDAsReporterRequest) (res *activityUserAwardGrpc.ListActivityAwardsByActivityIDAsReporterResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("activity_user_awardImp->ListActivityAwardsByActivityIDAsReporter:%v", req)
	res = &activityUserAwardGrpc.ListActivityAwardsByActivityIDAsReporterResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}

	q := s.dao.Q
	ts := sqlc.PBTimestampToGoTime(req.Ts)
	activityID := req.ActivityId

	total, err := q.CountActivityUserAwardWithUserInfosByActivityID(ctx, sqlc.CountActivityUserAwardWithUserInfosByActivityIDParams{
		Created:    ts,
		ActivityID: activityID,
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	if total == 0 {
		// 不用继续调用listfunc
		return
	}

	rows, err := q.ListActivityUserAwardWithUserInfosByActivityID(ctx, sqlc.ListActivityUserAwardWithUserInfosByActivityIDParams{
		Limit:      req.Limit,
		Offset:     req.Offset,
		Created:    ts,
		ActivityID: activityID,
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.Total = total
	res.ActivityAwardsAsReporter = mapActivityAwardAsReporterEntityToPb(rows, transformActivityAwardAsReporterEntityToPb)
	return
}
